package org.proteored.miapeapi.xml.gi;

import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.datatype.XMLGregorianCalendar;

import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.exceptions.IllegalMiapeArgumentException;
import org.proteored.miapeapi.exceptions.MiapeDatabaseException;
import org.proteored.miapeapi.exceptions.MiapeSecurityException;
import org.proteored.miapeapi.interfaces.MiapeDate;
import org.proteored.miapeapi.interfaces.Project;
import org.proteored.miapeapi.interfaces.User;
import org.proteored.miapeapi.interfaces.ge.GEContact;
import org.proteored.miapeapi.interfaces.gi.AnalysisDesign;
import org.proteored.miapeapi.interfaces.gi.DataAnalysis;
import org.proteored.miapeapi.interfaces.gi.DataExtraction;
import org.proteored.miapeapi.interfaces.gi.DataReporting;
import org.proteored.miapeapi.interfaces.gi.GIAdditionalInformation;
import org.proteored.miapeapi.interfaces.gi.ImageAnalysisSoftware;
import org.proteored.miapeapi.interfaces.gi.ImageGelInformatics;
import org.proteored.miapeapi.interfaces.gi.ImagePreparationStep;
import org.proteored.miapeapi.interfaces.gi.ImageProcessing;
import org.proteored.miapeapi.interfaces.gi.MiapeGIDocument;
import org.proteored.miapeapi.interfaces.persistence.PersistenceManager;
import org.proteored.miapeapi.interfaces.xml.MiapeXmlFile;
import org.proteored.miapeapi.interfaces.xml.XmlMiapeFactory;
import org.proteored.miapeapi.validation.ValidationReport;
import org.proteored.miapeapi.validation.gi.MiapeGIValidator;
import org.proteored.miapeapi.xml.gi.autogenerated.GIAnalysisDesign;
import org.proteored.miapeapi.xml.gi.autogenerated.GIDataAnalysis;
import org.proteored.miapeapi.xml.gi.autogenerated.GIDataExtraction;
import org.proteored.miapeapi.xml.gi.autogenerated.GIDataReporting;
import org.proteored.miapeapi.xml.gi.autogenerated.GIImage;
import org.proteored.miapeapi.xml.gi.autogenerated.GIImagePreparationStep;
import org.proteored.miapeapi.xml.gi.autogenerated.GIImageProcessing;
import org.proteored.miapeapi.xml.gi.autogenerated.GIMIAPEGI;
import org.proteored.miapeapi.xml.gi.autogenerated.MIAPEContactType;
import org.proteored.miapeapi.xml.gi.autogenerated.MIAPEProject;
import org.proteored.miapeapi.xml.gi.autogenerated.MIAPESoftwareType;
import org.proteored.miapeapi.xml.gi.autogenerated.ParamType;
import org.proteored.miapeapi.xml.gi.util.Utils;
import org.proteored.miapeapi.xml.miapeproject.UserImpl;

public class MiapeGIDocumentImpl implements MiapeGIDocument {
	private final GIMIAPEGI miapeGIXML;
	private PersistenceManager dbManager;
	private final ControlVocabularyManager cvUtil;
	private final User user;
	private final XmlMiapeFactory<MiapeGIDocument> xmlFactory;
	private int id;
	private Map<String, GIImage> imageMap;

	public MiapeGIDocumentImpl(GIMIAPEGI miapeGI,
			ControlVocabularyManager cvUtil, PersistenceManager dbManager,
			String userName, String password) throws MiapeDatabaseException,
			MiapeSecurityException {
		this(miapeGI, dbManager.getUser(userName, password), cvUtil, userName,
				password);
		this.dbManager = dbManager;
		imageMap = initImageMap();

	}

	public MiapeGIDocumentImpl(GIMIAPEGI miapeGI, User owner,
			ControlVocabularyManager cvUtil, String userName, String password) {
		miapeGIXML = miapeGI;
		if (owner != null)
			user = owner;
		else {
			if (miapeGI != null && miapeGI.getMIAPEProject() != null)
				user = new UserImpl(miapeGI.getMIAPEProject().getOwnerName(),
						userName, password);
			else
				user = null;
		}
		this.cvUtil = cvUtil;
		xmlFactory = MiapeGIXmlFactory.getFactory();
		if (miapeGI != null)
			id = miapeGI.getId();
		imageMap = initImageMap();

	}

	private Map<String, GIImage> initImageMap() {
		Map<String, GIImage> mapping = new HashMap<String, GIImage>();
		List<GIImage> giImage = miapeGIXML.getGIImage();
		if (giImage != null) {
			for (GIImage imageXML : giImage) {
				mapping.put(imageXML.getId(), imageXML);
			}
		}
		return mapping;
	}

	@Override
	public Set<GIAdditionalInformation> getAdditionalInformations() {
		Set<GIAdditionalInformation> additionalInfos = new HashSet<GIAdditionalInformation>();
		List<ParamType> giAdditionalInformation = miapeGIXML
				.getGIAdditionalInformation();
		if (giAdditionalInformation != null) {
			for (ParamType addInfoXML : giAdditionalInformation) {
				additionalInfos.add(new AdditionalInformationImpl(addInfoXML));
			}
		}
		return additionalInfos;
	}

	@Override
	public Set<AnalysisDesign> getAnalysisDesigns() {
		Set<AnalysisDesign> analysisDesigns = new HashSet<AnalysisDesign>();
		List<GIAnalysisDesign> giAnalysisDesign = miapeGIXML
				.getGIAnalysisDesign();
		if (giAnalysisDesign != null) {
			for (GIAnalysisDesign xmlAnalysisDesign : giAnalysisDesign) {
				analysisDesigns.add(new AnalysisDesignImpl(xmlAnalysisDesign));
			}
		}
		return analysisDesigns;
	}

	@Override
	public Set<ImageAnalysisSoftware> getImageAnalysisSoftwares() {
		Set<ImageAnalysisSoftware> imageAnalysisSoftwares = new HashSet<ImageAnalysisSoftware>();
		List<MIAPESoftwareType> giImageAnalysisSoftware = miapeGIXML
				.getGIImageAnalysisSoftware();
		if (giImageAnalysisSoftware != null) {
			for (MIAPESoftwareType xmlSoftware : giImageAnalysisSoftware) {
				imageAnalysisSoftwares.add(new ImageAnalysSoftwareImpl(
						xmlSoftware));
			}
		}
		return imageAnalysisSoftwares;
	}

	@Override
	public GEContact getContact() {
		MIAPEContactType giContact = miapeGIXML.getGIContact();
		if (giContact != null)
			return new ContactImpl(giContact);

		return null;
	}

	@Override
	public Set<DataAnalysis> getDataAnalysises() {
		Set<DataAnalysis> dataAnalysises = new HashSet<DataAnalysis>();
		List<GIDataAnalysis> giDataAnalysis = miapeGIXML.getGIDataAnalysis();
		if (giDataAnalysis != null) {
			for (GIDataAnalysis xmlDataAnalysis : giDataAnalysis) {
				dataAnalysises.add(new DataAnalysisImpl(xmlDataAnalysis));
			}
		}
		return dataAnalysises;
	}

	@Override
	public Set<DataExtraction> getDataExtractions() {
		Set<DataExtraction> dataExtractions = new HashSet<DataExtraction>();
		List<GIDataExtraction> giDataExtraction = miapeGIXML
				.getGIDataExtraction();
		if (giDataExtraction != null) {
			for (GIDataExtraction xmlDataExtraction : giDataExtraction) {
				dataExtractions.add(new DataExtractionImpl(xmlDataExtraction,
						imageMap));
			}
		}

		return dataExtractions;
	}

	@Override
	public Set<DataReporting> getDataReportings() {
		Set<DataReporting> dataReportings = new HashSet<DataReporting>();
		List<GIDataReporting> giDataReporting = miapeGIXML.getGIDataReporting();
		if (giDataReporting != null) {
			for (GIDataReporting xmlDataReporting : giDataReporting) {
				dataReportings.add(new DataReportingImpl(xmlDataReporting));
			}
		}
		return dataReportings;
	}

	@Override
	public String getElectrophoresisType() {
		ParamType electrophoresisType = miapeGIXML.getElectrophoresisType();
		if (electrophoresisType != null)
			return Utils.writeParam(electrophoresisType);
		else
			return null;
	}

	@Override
	public int getGEDocumentReference() {
		if (miapeGIXML.getMIAPEGERef() == null)
			return -1;
		return miapeGIXML.getMIAPEGERef();
		/*
		 * if (dbManager != null && dbManager.getMiapeGEDatabaseManager() !=
		 * null) { try { return
		 * dbManager.getMiapeGEDatabaseManager().retrieve(miapeGIXML
		 * .getMIAPEGERef(), userName, password); } catch
		 * (MiapeDatabaseException e) { e.printStackTrace(); } catch
		 * (MiapeSecurityException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
		 * return null;
		 */

	}

	@Override
	public Set<ImageProcessing> getImageProcessings() {
		Set<ImageProcessing> imageProcessings = new HashSet<ImageProcessing>();
		List<GIImageProcessing> giImageProcessing = miapeGIXML
				.getGIImageProcessing();
		if (giImageProcessing != null) {
			for (GIImageProcessing xmlImageProcessing : giImageProcessing) {
				imageProcessings.add(new ImageProcessingImpl(
						xmlImageProcessing, imageMap));
			}
		}
		return imageProcessings;
	}

	@Override
	public Set<ImageGelInformatics> getImages() {
		Set<ImageGelInformatics> images = new HashSet<ImageGelInformatics>();
		List<GIImage> giImage = miapeGIXML.getGIImage();
		if (giImage != null) {
			for (GIImage imageXML : giImage) {
				images.add(new ImageImpl(imageXML));
			}
		}
		return images;
	}

	@Override
	public Set<ImageAnalysisSoftware> getImagePreparationSoftwares() {
		Set<ImageAnalysisSoftware> imagePreparationSoftwares = new HashSet<ImageAnalysisSoftware>();
		List<MIAPESoftwareType> giImagePreparationSoftware = miapeGIXML
				.getGIImagePreparationSoftware();
		if (giImagePreparationSoftware != null) {
			for (MIAPESoftwareType imagePreparationSoftwareXML : giImagePreparationSoftware) {
				imagePreparationSoftwares.add(new ImageAnalysisSoftwareImpl(
						imagePreparationSoftwareXML));
			}
		}
		return imagePreparationSoftwares;
	}

	@Override
	public Set<ImagePreparationStep> getImagePreparationSteps() {
		Set<ImagePreparationStep> preparationSteps = new HashSet<ImagePreparationStep>();
		List<GIImagePreparationStep> giImagePreparationStep = miapeGIXML
				.getGIImagePreparationStep();
		if (giImagePreparationStep != null) {
			for (GIImagePreparationStep xmlPreparationStep : giImagePreparationStep) {
				preparationSteps.add(new ImagePreparationStepImpl(
						xmlPreparationStep));
			}
		}
		return preparationSteps;
	}

	@Override
	public String getReference() {
		return miapeGIXML.getReference();
	}

	@Override
	public MiapeDate getDate() {
		if (miapeGIXML.getDate() == null)
			return null;

		return new MiapeDate(miapeGIXML.getDate());
	}

	@Override
	public int getId() {
		return id;
	}

	@Override
	public Date getModificationDate() {
		XMLGregorianCalendar modificationDate = miapeGIXML
				.getModificationDate();
		if (modificationDate != null) {
			return modificationDate.toGregorianCalendar().getTime();
		}
		return null;
	}

	@Override
	public String getName() {
		return miapeGIXML.getName();
	}

	@Override
	public User getOwner() {
		return user;
	}

	@Override
	public String getAttachedFileLocation() {
		return miapeGIXML.getAttachedFileLocation();
	}

	@Override
	public Project getProject() {
		if (id > 0 && dbManager != null) {
			try {
				return dbManager
						.getMiapeGIPersistenceManager()
						.getMiapeById(id, user.getUserName(),
								user.getPassword()).getProject();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		MIAPEProject project = miapeGIXML.getMIAPEProject();
		if (project != null)
			return new ProjectImpl(project, user, dbManager);
		return null;
	}

	@Override
	public Boolean getTemplate() {
		return miapeGIXML.isTemplate();
	}

	@Override
	public String getVersion() {
		return miapeGIXML.getVersion();
	}

	@Override
	public void delete(String userName, String password)
			throws MiapeDatabaseException, MiapeSecurityException {
		if (dbManager != null
				&& dbManager.getMiapeGIPersistenceManager() != null) {
			dbManager.getMiapeGIPersistenceManager().deleteById(getId(),
					userName, password);
		}
		throw new MiapeDatabaseException(
				"The persistance method is not defined.");
	}

	@Override
	public int store() throws MiapeDatabaseException, MiapeSecurityException {
		if (dbManager != null
				&& dbManager.getMiapeGIPersistenceManager() != null) {
			id = dbManager.getMiapeGIPersistenceManager().store(this);
		}
		throw new MiapeDatabaseException(
				"The persistance method is not defined.");
	}

	@Override
	public MiapeXmlFile<MiapeGIDocument> toXml() {
		if (xmlFactory != null) {
			xmlFactory.toXml(this, cvUtil);
		}
		throw new IllegalMiapeArgumentException(
				"The xml Factory is not defined.");
	}

	@Override
	public ValidationReport getValidationReport() {
		return MiapeGIValidator.getInstance().getReport(this);
	}
}
